﻿/// ===============================================================================
/// Copyright (C) 2011  Ron Cresswell
/// ===============================================================================
/// This program is free software; you can redistribute it and/or
/// modify it under the terms of the GNU General Public License
/// as published by the Free Software Foundation; either version 2
/// of the License, or (at your option) any later version.
/// 
/// This program is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
/// GNU General Public License for more details.
/// 
/// You should have received a copy of the GNU General Public License
/// along with this program; if not, write to the Free Software
/// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
/// ===============================================================================
/// 
/// Project:        SharePoint Filtered Search
/// Author:         Ron Cresswell (ron.cresswell@angrymansoftware.com.au)
/// Company:        Angry Man Software
/// Date:           18/07/2011 (18 July 2011)  
/// Version:        0.97 (Beta)
///
/// ===============================================================================
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Microsoft.Office.Server.Search.WebControls;
using System.Globalization;
using Microsoft.Office.Server;
using Microsoft.SharePoint;
using System.Reflection;
using System.Xml;
using System.Web;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Utilities;

namespace AngryManSoftware.WebParts
{
    class AMSortSearchResult : IComparer<AMSearchResult>
    {

        #region IComparer<AMSearchResult> Members

        /// <summary>
        /// Compare two search results based on rank
        /// </summary>
        /// <param name="x">First Search Result</param>
        /// <param name="y">Second Search Result</param>
        /// <returns></returns>
        public int Compare(AMSearchResult x, AMSearchResult y)
        {
            if (x == null)
            {
                if (y == null)
                {
                    // If x is null and y is null, they're
                    // equal. 
                    return 0;
                }
                else
                {
                    // If x is null and y is not null, y
                    // is greater. 
                    return -1;
                }
            }
            else // trivial cases dealt with. Now sort properly
            {
                /*
                 * Sort should be based on hits and where they appear.
                 * Highest rank: Hits in metadata + hits in body
                 * Next: Hits in metadata only
                 * Lowest: Hits in body only
                 * 
                 * Within each of those categories, rank according to Search Engine Ranking
                 * 
                 * If we run two queries (one for metadata), we could simply ensure that 
                 * if a document comes up in the second query that we already have, we add
                 * the new rank to the old rank. That way this routine can be kept very simple
                 * and based only on the Rank.
                 * 
                 */

                if (x.Rank == y.Rank)
                {
                    return 0;
                }
                else if (x.Rank > y.Rank)
                {
                    return -1;
                }
                else // y.Rank > x.Rank
                {
                    return 1;
                }
            }
        }

        #endregion
    }

    class AMSearchResult
    {
        #region properties        

        private int rank;
        /// <summary>
        /// Ranking of the result determined by SharePoint
        /// </summary>
        public int Rank
        {
            get { return rank; }
            set { rank = value; }
        }

        private string hit_highlighted_summary;
        /// <summary>
        /// Text returned by search engine showing search term in context
        /// </summary>
        public string HitHighlightedSummary
        {
            get { return hit_highlighted_summary; }
            set { hit_highlighted_summary = value; }
        }

        private string filename;
        /// <summary>
        /// filename of the document
        /// </summary>
        public string FileName
        {
            get { return filename; }
            set { filename = value; }
        }
        private string parent_lib;
        /// <summary>
        /// parent library url for the document
        /// </summary>
        public string ParentLib
        {
            get { return parent_lib; }
            set { parent_lib = value; }
        }
        
        private string url;
        /// <summary>
        /// URL corresponding to the document
        /// </summary>
        public string Url
        {
            get { return url; }
            set { url = value; }
        }
        private Hashtable search_col_vals;
        public Hashtable SearchColumnValues
        {
            get { return search_col_vals; }
            set { search_col_vals = value; }
        }
        private List<AMMatch> matches;
        public List<AMMatch> Matches
        {
            get { return matches; }
            set { matches = value; }
        }
        #endregion 

        #region constructor
        public AMSearchResult()
        {
            url = "";
            hit_highlighted_summary = "";
            search_col_vals = new Hashtable();
            matches = new List<AMMatch>();
        }
        #endregion

        #region methods

        /// <summary>
        /// Find and highlight in bold any occurances of a query string in the HitHighlightedSummary
        /// </summary>
        /// <param name="query">The string to look for, and highlight if found</param>
        /// <returns>html formatted text with query string in bold</returns>
        public string FormattedHitHighlight(string query)
        {
            if (hit_highlighted_summary == "")
            {
                return "";
            }
            else
            {
                string foundText = hit_highlighted_summary;
                string retString = "";
                int foundLen = foundText.Length;
                int queryLen = query.Length;
                List<string> subs = new List<string>();
                for (int i = 0; i < foundLen - queryLen; i++)
                {
                    string bit = foundText.Substring(i, queryLen);
                    if (bit.ToLower() == query.ToLower())
                    {
                        if (!subs.Contains(bit))
                        {
                            subs.Add(bit);
                        }
                    }
                }
                foreach (string bit in subs)
                {
                    string nbit = "<b>" + bit + "</b>";
                    retString = foundText.Replace(bit, nbit);
                    foundText = retString;
                }
                return foundText;
            }
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("filename: " + this.filename);
            sb.AppendLine("hithighlighted summary: " + this.hit_highlighted_summary);
            sb.AppendLine("rank: " + this.rank.ToString());
            sb.AppendLine("url: " + this.url);
            sb.AppendLine("parent library URL: " + this.parent_lib);
            sb.AppendLine("search column values:- ");
            foreach (string scol in search_col_vals.Keys)
            {
                sb.AppendLine("--> Search Column: " + scol + ", value= " + (string)search_col_vals[scol]);
            }            
            sb.AppendLine("matches:-");
            foreach (AMMatch m in this.matches)
            {
                sb.Append(m.ToString());
            }
            return sb.ToString();
        }

        #endregion
    }

    /// <summary>
    /// Object representing a match to a field value
    /// </summary>
    class AMMatch
    {
        #region properties
        private string field_name;
        /// <summary>
        /// Display name of matching field
        /// </summary>
        public string FieldName
        {
            get { return field_name; }
            set { field_name = value; }
        }
        
        private string field_value;
        /// <summary>
        /// Value of matching column
        /// </summary>
        public string FieldValue
        {
            get { return field_value; }
            set { field_value = value; }
        }
        private string field_internal_name;
        /// <summary>
        /// Internal name of matching field
        /// </summary>
        public string FieldInternalName
        {
            get { return field_internal_name; }
            set { field_internal_name = value; }
        }
        private string field_html_value;
        /// <summary>
        /// Html formatted version of matching column value (for filtering)
        /// </summary>
        public string FieldHtmlValue
        {
            get { return field_html_value; }
            set { field_html_value = value; }
        }

        private string parent_library_name;
        /// <summary>
        /// Value of matching column
        /// </summary>
        public string ParentLibraryName
        {
            get { return parent_library_name; }
            set { parent_library_name = value; }
        }
        private string parent_default_view_url;
        /// <summary>
        /// Value of matching column
        /// </summary>
        public string ParentDefaultViewURL
        {
            get { return parent_default_view_url; }
            set { parent_default_view_url = value; }
        }

        #endregion

        #region constructor
        public AMMatch()
        {
            field_name = "";
            field_value = "";
            field_internal_name = "";
            field_html_value = "";
            parent_library_name = "";
            parent_default_view_url = "";
        }
        #endregion

        #region methods
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("--> field_name: " + this.field_name);
            sb.AppendLine("--> field_internal_name : " + this.field_internal_name);
            sb.AppendLine("--> field_value : " + this.field_value);
            sb.AppendLine("--> field_html_value : " + this.field_html_value);
            sb.AppendLine("--> parent_default_view_url : " + this.parent_default_view_url);
            sb.AppendLine("--> parent_library_name : " + this.parent_library_name);
            return sb.ToString();
        }
        #endregion
    }


    
}
